package com.starry.gateway.filter;

import cn.hutool.core.lang.UUID;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.Arrays;
import java.util.List;

import static com.starry.core.common.constants.CommonConstant.GATEWAY_BEGIN_TIME_STR;
import static com.starry.core.common.constants.CommonConstant.TRACK_ID_STR;

/**
 * @Description 请求日志过滤器
 * @Author xiaoke
 *
 */
@Slf4j
@Component
public class RequestLogFilter implements GlobalFilter, Ordered {
    static String reqInfo = """
            
            ============== Request start ===================
            ==> url: {}
            ==> method: {}
            {}
            ============== Request end ===================
            """;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        // 记录请求：url、方法、header
        URI uri = request.getURI();
        String method = request.getMethod().name();
        HttpHeaders headers = request.getHeaders();
        StringBuilder headerStr = new StringBuilder();
        String trackId = null;
        for (String headerName : headers.keySet()) {
            List<String> headerValue = headers.get(headerName);
            assert headerValue != null;
            headerStr.append("==> headers: ").append(headerName).append(":")
                    .append(Arrays.toString(headerValue.toArray())).append("\n");
            if (TRACK_ID_STR.equals(headerName))
                trackId = headerValue.get(0);
        }
        String finalTrackId = null == trackId ? UUID.fastUUID().toString() : trackId;
        ServerHttpRequest req = exchange.getRequest().mutate()
                .headers(httpHeaders -> {
                    // 计算用时
                    httpHeaders.add(GATEWAY_BEGIN_TIME_STR, String.valueOf(System.currentTimeMillis()));
                    // trackId
                    httpHeaders.add(TRACK_ID_STR, finalTrackId);
                })
                .build();
        return chain.filter(exchange.mutate().request(req).build())
                .then(Mono.fromRunnable(() -> writeAccessLog(uri, method, headerStr)));
    }

    private void writeAccessLog(URI uri, String method, StringBuilder headerStr) {
        headerStr.delete(headerStr.lastIndexOf("\n"), headerStr.length());
        log.info(reqInfo, uri, method, headerStr);
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }

}
